﻿using System;
using UnityEngine;
using UnityEngine.UI;

namespace CGF
{
    //传入的RectTransform，只需一层Image即可，不需要任何子节点
    public class TurnPage : MonoBehaviour
    {
        public bool canDragToTurn = true;
        public Sprite backSprite, shadowSprite, contentSprite;
        public AudioClip dragSound;

        //需要测试时，加上public即可，把定位节点拖上来
        [Header("Debug")]
        RectTransform touchPoint;
        RectTransform rectL, rectR, rectT, rectB;

        internal Vector2 topLeft, bottomLeft, topRight, bottomRight;
        internal RectTransform rectTransform { get { return transform as RectTransform; } }
        internal RectTransform mask, backClone, contentClone, shadow;
        internal Vector2 symmetryPoint;
        internal float cardWidth, cardHeight;
        internal Line lineL, lineR, lineT, lineB;
        internal bool IsTransverse { get { return rectTransform.localEulerAngles.z == 90 || rectTransform.localEulerAngles.z == 270; } }
        internal Action onStartTurnOver, onTouchDownCurl, onCurlingUpdate, onTouchUpCurl, onTurnOverSucceed;
        internal bool hadDragTouchDown, isDraging;
        internal Vector2 dragPos;
        internal bool isCurling;
        internal Vector2 offset;

        private TurnPage_Method currMethod;
        private Rect rectBottom, rectLeft, rectRight, rectTop;
        private CButton button;
        private Image maskImg, backCloneImg, contentImg, shadowImg;
        private bool hadTriggerStartTurnOverEvent, canTriggerOnStartCurlEvent, hadTurnOverSucceed;
        private Canvas canvas;
        private Camera uiCamera;
        private Vector2 ScreenUISize { get { return (canvas.transform as RectTransform).sizeDelta; } }

        public void Awake()
        {
            CanvasScaler canvasScaler = rectTransform.GetComponentInParent<CanvasScaler>();
            canvas = canvasScaler.GetComponent<Canvas>();
            if (canvas && canvas.renderMode != RenderMode.ScreenSpaceOverlay)
            {
                uiCamera = canvas.worldCamera;
            }

            button = rectTransform.GetComponent<CButton>();
            if (button == null) button = this.rectTransform.gameObject.AddComponent<CButton>();
            button.triggerInterval = 0;
            button.SetPress(OnTouchDown);

            if (touchPoint) InitDebugImage(touchPoint, true);
            if (rectL) InitDebugImage(rectL, false);
            if (rectR) InitDebugImage(rectR, false);
            if (rectT) InitDebugImage(rectT, false);
            if (rectB) InitDebugImage(rectB, false);

            InitPos(canDragToTurn);
        }

        private void InitDebugImage(RectTransform trans, bool pivotCenter)
        {
            trans.pivot = pivotCenter ? new Vector2(0.5f, 0.5f) : new Vector2(0, 1);
            Image img = trans.GetComponent<Image>();
            img.raycastTarget = false;
            Color color = img.color;
            color.a = 0.3f;
            img.color = color;
        }

        public void Update()
        {
            if (currMethod != null)
            {
                currMethod.Update();
                if (isCurling)
                {
                    if (onCurlingUpdate != null)
                    {
                        onCurlingUpdate();
                    }
                    if (canTriggerOnStartCurlEvent)
                    {
                        if (onTouchDownCurl != null)
                        {
                            onTouchDownCurl();
                        }
                        canTriggerOnStartCurlEvent = false;
                    }
                }
            }
        }

        public void SetBackSprite(Sprite sprite)
        {
            this.backSprite = sprite;
        }

        public void SetShadowSprite(Sprite sprite)
        {
            this.shadowSprite = sprite;
        }

        public void SetContentSprite(Sprite sprite)
        {
            this.contentSprite = sprite;
        }

        /// <summary>
        /// 初始化卡片的各个位置关系,参数为true表示可触摸翻牌，false表示不可触摸，而用Drag()方法进行模拟自动播放
        /// </summary>
        public void InitPos(bool canDragToTurn)
        {
            this.canDragToTurn = canDragToTurn;
            hadTriggerStartTurnOverEvent = false;
            this.button.enabled = canDragToTurn;
            this.rectTransform.GetComponent<Image>().sprite = backSprite;
            Vector2 currPos = WorldToUGUIPoint(rectTransform.position);
            Vector2 size = new Vector2(rectTransform.rect.width, rectTransform.rect.height);
            Vector2 scale = rectTransform.localScale;
            if (!IsTransverse)
            {
                topLeft = currPos + new Vector2(-size.x * 0.5f * scale.x, size.y * 0.5f * scale.y);
                topRight = currPos + new Vector2(size.x * 0.5f * scale.x, size.y * 0.5f * scale.y);
                bottomLeft = currPos + new Vector2(-size.x * 0.5f * scale.x, -size.y * 0.5f * scale.y);
                bottomRight = currPos + new Vector2(size.x * 0.5f * scale.x, -size.y * 0.5f * scale.y);
            }
            else
            {
                topLeft = currPos + new Vector2(-size.y * 0.5f * scale.x, size.x * 0.5f * scale.y);
                topRight = currPos + new Vector2(size.y * 0.5f * scale.x, size.x * 0.5f * scale.y);
                bottomLeft = currPos + new Vector2(-size.y * 0.5f * scale.x, -size.x * 0.5f * scale.y);
                bottomRight = currPos + new Vector2(size.y * 0.5f * scale.x, -size.x * 0.5f * scale.y);
            }
            cardWidth = bottomRight.x - bottomLeft.x;
            cardHeight = topLeft.y - bottomLeft.y;
            lineL = new Line(topLeft, bottomLeft);
            lineR = new Line(topRight, bottomRight);
            lineT = new Line(topLeft, topRight);
            lineB = new Line(bottomLeft, bottomRight);
            float rectSize = IsTransverse ? cardHeight * 0.35f : cardWidth * 0.35f;
            rectBottom = new Rect(bottomLeft.x, bottomLeft.y + rectSize, cardWidth, rectSize);
            rectLeft = new Rect(topLeft.x, topLeft.y - rectSize, rectSize, cardHeight - rectSize * 2);
            rectRight = new Rect(topRight.x - rectSize, topRight.y - rectSize, rectSize, cardHeight - rectSize * 2);
            rectTop = new Rect(topLeft.x, topLeft.y, cardWidth, rectSize);
            offset = Vector2.zero;
            Transform parent = rectTransform.parent;
            for (int i = 0; i < 100; i++)
            {
                if (parent && !parent.GetComponent<CanvasScaler>())
                {
                    RectTransform rectTransform = parent as RectTransform;
                    if (rectTransform.anchorMin.x == rectTransform.anchorMax.x)
                    {
                        if (rectTransform.anchorMin.x == 1)
                        {
                            offset.x += ScreenUISize.x * 0.5f;
                        }
                        else if (rectTransform.anchorMin.x == 0)
                        {
                            offset.x -= ScreenUISize.x * 0.5f;
                        }
                    }
                    if (rectTransform.anchorMin.y == rectTransform.anchorMax.y)
                    {
                        if (rectTransform.anchorMin.y == 1)
                        {
                            offset.y -= ScreenUISize.y * 0.5f;
                        }
                        else if (rectTransform.anchorMin.y == 0)
                        {
                            offset.y += ScreenUISize.y * 0.5f;
                        }
                    }
                    offset -= rectTransform.anchoredPosition;
                    parent = parent.parent;
                    continue;
                }
                break;
            }
        }

        /// <summary>
        /// 外部拖拽翻牌（代码模拟而非触控或鼠标）,isDrag为false时表示已放开
        /// </summary>
        public void Drag(bool isDrag, Vector2 touchPos)
        {
            if (isDrag)
            {
                if (!hadDragTouchDown)
                {
                    hadDragTouchDown = OnTouchDown(touchPos);
                }
                isDraging = true;
                this.dragPos = touchPos;
            }
            else
            {
                isDraging = false;
            }
        }

        //还原成盖着的状态
        public void Resume()
        {
            Image image = this.rectTransform.GetComponent<Image>();
            image.sprite = backSprite;
            image.enabled = true;
            if (mask)
            {
                GameObject.Destroy(mask.gameObject);
            }
            currMethod = null;
            hadDragTouchDown = false;
            hadTurnOverSucceed = false;
            hadTriggerStartTurnOverEvent = false;
        }

        //翻开成功
        public void TurnOverFinish()
        {
            DestroyClone();
            this.rectTransform.GetComponent<Image>().sprite = contentSprite;
            hadTurnOverSucceed = true;
            this.button.enabled = false;
            if (onTurnOverSucceed != null)
            {
                onTurnOverSucceed();
            }
        }

        //翻开成功
        public void DestroyClone()
        {
            if (contentClone)
            {
                GameObject.Destroy(contentClone.gameObject);
            }
            if (mask)
            {
                GameObject.Destroy(mask.gameObject);
            }
            Image originCard = this.rectTransform.GetComponent<Image>();
            originCard.enabled = true;
            currMethod = null;
            this.button.enabled = canDragToTurn;
        }

        //按下时执行一次(来自触控或鼠标)
        private void OnTouchDown()
        {
            OnTouchDown(_TouchPos());
        }

        //按下时执行一次
        private bool OnTouchDown(Vector2 touchPos)
        {
            if (hadTurnOverSucceed)
            {
                return false;
            }

            if (touchPoint) touchPoint.anchoredPosition = touchPos;
            if (rectL)
            {
                rectL.anchoredPosition = rectLeft.position;
                rectL.sizeDelta = rectLeft.size;
            }
            if (rectR)
            {
                rectR.anchoredPosition = rectRight.position;
                rectR.sizeDelta = rectRight.size;
            }
            if (rectT)
            {
                rectT.anchoredPosition = rectTop.position;
                rectT.sizeDelta = rectTop.size;
            }
            if (rectB)
            {
                rectB.anchoredPosition = rectBottom.position;
                rectB.sizeDelta = rectBottom.size;
            }

            if (TouchInRect(touchPos, rectBottom))
            {
                currMethod = new TurnPage_Method_Bottom(this);
            }
            else if (TouchInRect(touchPos, rectLeft))
            {
                currMethod = new TurnPage_Method_Left(this);
            }
            else if (TouchInRect(touchPos, rectRight))
            {
                currMethod = new TurnPage_Method_Right(this);
            }
            else if (TouchInRect(touchPos, rectTop))
            {
                currMethod = new TurnPage_Method_Top(this);
            }
            if (currMethod == null)
            {
                Debug.LogError("按下位置错误，不触发任何翻转方法");
                return false;
            }
            if (!mask)
            {
                Vector2 size = rectTransform.sizeDelta;
                Vector2 scale = rectTransform.localScale;

                mask = new GameObject("Mask", typeof(Image), typeof(Mask)).transform as RectTransform;
                mask.SetParent(rectTransform.parent, false);
                mask.GetComponent<Mask>().showMaskGraphic = false;
                maskImg = mask.GetComponent<Image>();
                maskImg.raycastTarget = false;
                float _size = Mathf.Max(size.x * 3f * scale.x, size.y * 3f * scale.y);
                mask.sizeDelta = new Vector2(_size, _size);
                maskImg.enabled = false;

                backClone = new GameObject("Back_Clone", typeof(Image)).transform as RectTransform;
                backClone.SetParent(mask, false);
                backClone.anchorMin = rectTransform.anchorMin;
                backClone.anchorMax = rectTransform.anchorMax;
                backClone.sizeDelta = size * scale;
                backCloneImg = backClone.GetComponent<Image>();
                backCloneImg.sprite = this.rectTransform.GetComponent<Image>().sprite;
                backCloneImg.color = this.rectTransform.GetComponent<Image>().color;
                backCloneImg.raycastTarget = false;
                backCloneImg.enabled = false;

                contentClone = new GameObject("Content_Clone", typeof(Image), typeof(Mask)).transform as RectTransform;
                contentClone.SetParent(mask, false);
                contentClone.GetComponent<Mask>().showMaskGraphic = true;
                contentImg = contentClone.GetComponent<Image>();
                contentImg.sprite = contentSprite;
                contentImg.raycastTarget = false;
                contentImg.enabled = false;
                contentClone.sizeDelta = size * scale;

                shadow = new GameObject("Shadow", typeof(Image)).transform as RectTransform;
                shadow.SetParent(contentClone, false);
                shadowImg = shadow.GetComponent<Image>();
                shadowImg.color = new Color(0, 0, 0, 0.5f);
                shadowImg.sprite = shadowSprite;
                shadowImg.raycastTarget = false;
                shadowImg.enabled = false;
                shadow.sizeDelta = new Vector2(cardHeight * 3f, 100f);
                shadow.pivot = new Vector2(0.5f, 0.8f);
            }

            if (this.rectTransform.gameObject.activeInHierarchy)
            {
                ShowContentDelay(maskImg, backCloneImg, contentImg, shadowImg);
            }

            currMethod.SetTargetsPivot(touchPos);
            if (!hadTriggerStartTurnOverEvent)
            {
                onStartTurnOver?.Invoke();
                hadTriggerStartTurnOverEvent = true;
            }
            isCurling = true;
            canTriggerOnStartCurlEvent = true;

            return true;
        }

        //获取当前点击的位置
        public Vector2 _TouchPos()
        {
            Vector2 touchPos = ScreenToUGUIPoint(Input.mousePosition);
            return touchPos;
        }

        //判断当前点击在卡片哪一个部位，以此判断翻卡的方向
        private bool TouchInRect(Vector2 touchPos, Rect rect)
        {
            if (touchPos.x > rect.x - 10 && touchPos.x < rect.x + rect.width + 10)
            {
                if (touchPos.y < rect.y + 10 && touchPos.y > rect.y - rect.height - 10)
                {
                    return true;
                }
            }
            return false;
        }

        //旋转到90度
        public async void RotateCard90Degrees(Action onRotateFinished)
        {
            Vector3 toAngle = Vector3.zero;
            if (rectTransform.localEulerAngles.z == 0f)
            {
                toAngle = new Vector3(0, 0, 90f);
            }
            else if (rectTransform.localEulerAngles.z == 90f)
            {
                toAngle = new Vector3(0, 0, 180f);
            }
            else if (rectTransform.localEulerAngles.z == 180f)
            {
                toAngle = new Vector3(0, 0, 270f);
            }
            else if (rectTransform.localEulerAngles.z == 270f)
            {
                toAngle = new Vector3(0, 0, 360f);
            }
            while (true)
            {
                rectTransform.localEulerAngles = Vector3.Lerp(rectTransform.localEulerAngles, toAngle, 0.5f);
                if (Vector3.Distance(rectTransform.localEulerAngles, toAngle) < 0.1f)
                {
                    rectTransform.localEulerAngles = toAngle;
                    InitPos(canDragToTurn);
                    onRotateFinished?.Invoke();
                    break;
                }
                await CTask.Wait(0.01f);
            }
        }

        //延迟两帧显示
        private async void ShowContentDelay(Image maskImg, Image backCloneImg, Image contentImg, Image shadowImg)
        {
            await CTask.Wait(0.1f);
            this.rectTransform.GetComponent<Image>().enabled = false;
            maskImg.enabled = true;
            backCloneImg.enabled = true;
            contentImg.enabled = true;
            shadowImg.enabled = true;
        }

        private Vector2 WorldToUGUIPoint(Vector3 worldPos)
        {
            Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(uiCamera, worldPos);
            return ScreenToUGUIPoint(screenPos);
        }

        private Vector2 ScreenToUGUIPoint(Vector2 screenPos)
        {
            RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, screenPos, uiCamera, out Vector2 uiPos);
            return uiPos;
        }
    }
}